package demo.game.chess.common;

import java.io.Serializable;
import java.util.List;

public abstract class AbstractChessPiece implements Serializable {

	private final ChessCell initialPosition;

	public AbstractChessPiece(final ChessCell initialPosition) {
		super();
		this.initialPosition = initialPosition;
	}

	protected final void checkObstacle(final ChessBoard board,
			final ChessCell origin, final ChessCell target)
			throws MoveException {

		List<ChessCell> path = origin.getPathTo(target);
		//Log.debug(this + ": path: " + path);
		for (ChessCell c : origin.getPathTo(target)) {
			AbstractChessPiece p = board.getPieceAt(c);
			if (null != p) {
				throw new MoveException(new ChessMove(origin, target),
						"hasObstacle origin=" + origin + " target=" + target
								+ " obstacle=" + p + " at " + c + " path="
								+ path);
			}
		}
	}

	/** 
	 * Check piece-specific move rules.
	 */
	protected abstract ChessMove createPieceSpecificMove(ChessBoard board,
			ChessCell origin, ChessCell target) throws MoveException;

	public final ChessMove createValidMove(final ChessBoard board,
			final ChessCell origin, final ChessCell target)
			throws MoveException {
		//Log.debug(this + " createValidMove from " + origin + " to " + target);
		if (!isCellAvailable(board, target)) {
			throw new MoveException(new ChessMove(origin, target),
					"Target has a piece of same color");
		}
		ChessMove result = createPieceSpecificMove(board, origin, target);
		//		Log.debug(this + " createValidMove from " + origin + " to " + target
		//				+ " result=" + result);
		return result;

	}

	@Override
	public boolean equals(final Object object) {
		if (null == object) {
			return false;
		}
		if (!this.getClass().equals(object.getClass())) {
			return false;
		}
		return getId() == ((AbstractChessPiece) object).getId();
	}

	public EnumChessColor getColor() {
		// the pieces at the top of the board are black.
		return (this.getInitialPosition().getRow() <= 1) ? EnumChessColor.black
				: EnumChessColor.white;
	}

	public int getId() {
		return this.initialPosition.getRow() * 10
				+ +this.initialPosition.getColumn();
	}

	public ChessCell getInitialPosition() {
		return this.initialPosition;
	}

	public abstract EnumChessPiece getType();

	@Override
	public int hashCode() {
		return getId();
	}

	/**
	 * Check that the target cell is blank 
	 * or the the target cell contains an opposite-side piece.
	 * 
	 * @param board
	 * @param origin
	 * @param target
	 * @return
	 */
	protected boolean isCellAvailable(final ChessBoard board,
			final ChessCell target) throws MoveException {
		AbstractChessPiece pieceAtTarget = board.getPieceAt(target);
		return (pieceAtTarget == null || pieceAtTarget.getColor() != this
				.getColor());

	}

	@Override
	public String toString() {
		return getType() + "_" + getColor() + "_id" + getId();
	}
}
